<template>
    <div v-loading="pageLoading">
        <!-- 返回 -->
        <el-card class="!border-none" shadow="never">
            <el-page-header
                :content="pageTitle"
                @back="emits('listen', scene, 'lists', 0)"
            />
        </el-card>

        <!-- 表单 -->
        <el-form
            ref="formRef"
            :model="formData"
            :rules="formRules"
            label-width="80px"
            class="mt-4"
        >
            <!-- 基本配置 -->
            <el-card shadow="never" class="!border-none">
                <div class="text-xl font-medium mb-6">基础配置</div>
                <el-form-item label="AI图标" prop="logo">
                    <material-picker
                        v-model="formData.logo"
                        :limit="1"
                    />
                </el-form-item>
                <el-form-item label="AI通道" prop="channel">
                    <div class="w-[400px]">
                        <el-select
                            v-model="formData.channel"
                            placeholder="请选择AI通道"
                            clearable
                            @change="changeChannel"
                        >
                            <el-option
                                v-for="(item, key) in currentChannels"
                                :value="key"
                                :label="item.name"
                                :key="key"
                            />
                        </el-select>
                    </div>
                </el-form-item>
                <el-form-item label="模型标识" prop="mark">
                    <div class="w-[400px]">
                        <el-input
                            v-model="formData.mark"
                            :disabled="props.type !== 'add'"
                            placeholder="请输入唯一的标识"
                            maxlength="100"
                        />
                    </div>
                </el-form-item>
                <el-form-item label="渠道名称" prop="name">
                    <div class="w-[400px]">
                        <el-input
                            v-model="formData.name"
                            placeholder="请输入模型名"
                            maxlength="100"
                        />
                    </div>
                </el-form-item>
                <el-form-item label="渠道描述" prop="intro">
                    <div class="w-[400px]">
                        <el-input
                            v-model.trim="formData.intro"
                            placeholder="请用一句简短的话描述一下"
                            type="textarea"
                            :rows="4"
                        />
                    </div>
                </el-form-item>
                <el-form-item label="渠道状态" prop="is_disable">
                    <div class="w-[400px]">
                        <el-radio-group v-model="formData.is_disable">
                            <el-radio :value="0">启用</el-radio>
                            <el-radio :value="1">停用</el-radio>
                        </el-radio-group>
                    </div>
                </el-form-item>
                <el-form-item
                    v-for="item in (formData.config as any[])"
                    :label="item.name"
                    :prop="item.key"
                    :key="item.key"
                    :rules="item.require ? [
                        {
                            required: item.require,
                            trigger: 'change',
                            validator(___rule: any, value: any, callback: any) {
                                if (item.key && !value) {
                                    callback(new Error(item.placeholder))
                                } else {
                                    callback()
                                }
                            }
                        }
                    ] : []"
                >
                    <div class="w-[400px]">
                        <template v-if="item.type === 'group'">
                            <div class="flex flex-wrap w-full">
                                <div v-for="conf in item.config" :key="conf.key" class="w-[50%] pr-[50px] pb-[20px]">
                                    <div class="flex items-center text-tx-regular text-xs">
                                        <span class="mr-[4px] mt-[2px]">{{ conf.name }}</span>
                                        <el-tooltip
                                            class="box-item"
                                            effect="dark"
                                            :content="conf.key + ': ' + conf.tips"
                                            placement="right"
                                        >
                                            <icon :size="16" name="el-icon-QuestionFilled" />
                                        </el-tooltip>
                                    </div>
                                    <template v-if="conf.type === 'slider'">
                                        <el-slider
                                            v-model="conf.default"
                                            :min="conf.range[0]"
                                            :max="conf.range[1]"
                                            :step="conf.step"
                                        />
                                    </template>
                                    <template v-if="conf.type === 'switch'">
                                        <el-switch v-model="formData.config[conf.key]" />
                                    </template>
                                </div>
                            </div>
                        </template>
                        <template v-if="item.type === 'switch'">
                            <el-switch v-model="item.default" />
                        </template>
                        <template v-if="item.type === 'input'">
                            <el-input
                                v-model.trim="item.default"
                                :placeholder="item.placeholder || '请输入'"
                            />
                            <div class="form-tips">{{ item.tips }}</div>
                        </template>
                        <template v-if="item.type === 'textarea'">
                            <el-input
                                v-model.trim="item.default"
                                :placeholder="item.placeholder || '请输入'"
                                type="textarea"
                                :rows="4"
                            />
                            <div class="form-tips">{{ item.tips }}</div>
                        </template>
                    </div>
                </el-form-item>
            </el-card>

            <!-- 子级模型 -->
            <el-card shadow="never" class="!border-none mt-4">
                <div class="flex items-center mb-[10px]">
                    <div class="text-xl font-medium mr-4">
                        模型配置
                        <el-tooltip
                            content="模型可自定义添加，点击旁边的新增按钮，务必正确填写 最大上下文 和 最大输出"
                            placement="right-start"
                            :teleported="true"
                        >
                            <span class="inline-flex text-tx-secondary">
                                <icon name="el-icon-QuestionFilled" />
                            </span>
                        </el-tooltip>
                    </div>
                    <el-button
                        type="primary"
                        link
                        @click="handleCreate"
                    >添加模型</el-button>
                </div>
                <div class="text-xs text-tx-placeholder">
                    注意: 『模型名称』必须要和模型提供方的名称一致，自定义名称您可以随意填写。
                </div>
                <el-table
                    ref="tableRef"
                    size="large"
                    class="mt-4"
                    row-key="id"
                    :data="formData.models"
                >
                    <el-table-column width="30">
                        <template #default>
                            <div class="move-icon cursor-move">
                                <icon name="el-icon-Rank" />
                            </div>
                        </template>
                    </el-table-column>
                    <el-table-column label="模型名称" min-width="120">
                        <template #default="{ row }">
                            <el-autocomplete
                                class="w-full"
                                v-model.trim="row.model"
                                :fetch-suggestions="suggestionModels"
                                placeholder="请输入模型名"
                                clearable
                            />
                        </template>
                    </el-table-column>
                    <el-table-column label="自定义名称" min-width="120">
                        <template #default="{ row }">
                            <el-input
                                v-model="row.alias"
                                placeholder="请输入自定名"
                            />
                        </template>
                    </el-table-column>
                    <el-table-column  label="tokens/1积分" min-width="110">
                        <template #default="{ row }">
                            <el-input
                                v-model="row.price"
                                type="number"
                                placeholder="0不消耗"
                            />
                        </template>
                    </el-table-column>
                    <el-table-column v-if="formData.scene === 'vector'" label="输出维度" min-width="100" required>
                        <template #default="{ row }">
                            <el-autocomplete
                                v-model="row.dimension"
                                :fetch-suggestions="suggestionDimension"
                                placeholder="维度"
                                clearable
                            />
                        </template>
                    </el-table-column>
                    <el-table-column v-if="formData.scene === 'chat'" label="上下文" min-width="100" required>
                        <template #default="{ row }">
                            <el-autocomplete
                                v-model="row.max_context"
                                :fetch-suggestions="suggestionMaxTokens"
                                placeholder="tokens"
                                clearable
                            />
                        </template>
                    </el-table-column>
                    <el-table-column v-if="formData.scene === 'chat'" label="最大输出" min-width="100" required>
                        <template #default="{ row }">
                            <el-autocomplete
                                v-model="row.max_output"
                                :fetch-suggestions="suggestionMaxTokens"
                                placeholder="tokens"
                                clearable
                            />
                        </template>
                    </el-table-column>
                    <el-table-column v-if="formData.scene === 'chat'" label="多模态" width="75">
                        <template #default="{ row }">
                            <el-switch
                                v-model="row.modal"
                                :before-change="() => handleModal(row)"
                                :active-value="1"
                                :inactive-value="0"
                            />
                        </template>
                    </el-table-column>
                    <el-table-column label="状态" width="75">
                        <template #default="{ row }">
                            <el-switch
                                v-model="row.status"
                                :before-change="() => handleStatus(row)"
                                :active-value="1"
                                :inactive-value="0"
                            />
                        </template>
                    </el-table-column>
                    <el-table-column label="操作" width="68" fixed="right">
                        <template #default="{ row, $index }">
                            <div>
                                <el-button
                                    :disabled="formData.models.length <= 1"
                                    type="danger"
                                    link
                                    @click="handleDelete($index, row.id)"
                                >
                                    删除
                                </el-button>
                            </div>
                        </template>
                    </el-table-column>
                </el-table>
            </el-card>
        </el-form>

        <!-- 按钮 -->
        <el-card shadow="never" class="!border-none mt-4 text-center">
            <el-button @click="emits('listen', scene, 'lists', 0)">取消</el-button>
            <el-button
                v-perms="['setting:ai:models:add', 'setting:ai:models:edit']"
                :loading="loading"
                type="primary"
                @click="handleSubmit"
            >保存</el-button>
        </el-card>
    </div>
</template>

<script setup lang="ts">
import type { ElTable } from 'element-plus'
import { nextTick, watch } from 'vue'
import feedback from '@/utils/feedback'
import aiModelsApi from '@/api/setting/ai/models'
import Sortable from 'sortablejs'

const emits = defineEmits(['listen'])
const props = defineProps({
    // 编辑ID
    id: {
        type: Number,
        default: 0
    },
    // 操作类型: [add, edit]
    type: {
        type: String,
        default: 'add'
    },
    // 操作场景: [chat, vector]
    scene: {
        type: String,
        default: 'chat'
    }
})

const tableRef = ref<InstanceType<typeof ElTable>>()

// 页面加载
const pageLoading = ref<boolean>(true)
// 提交加载
const loading = ref<boolean>(false)
// 表单引用
const formRef = shallowRef()
// 页面标题
const pageTitle = computed(() => {
    if (props.type === 'add') {
        return props.scene === 'chat' ? '新增对话模型' : '新增向量模型'
    }
    return props.scene === 'chat' ? '编辑对话模型' : '编辑向量模型'
})

// 模型通道
const channels = ref({
    chat_models: {},
    vector_models: {},
    ranking_models: {}
})

// 模型建议
const suggestionModels = ref([

])

// 令牌建议
const suggestionMaxTokens = shallowRef([
    { value: 512 },
    { value: 1024 },
    { value: 2048 },
    { value: 4096 },
    { value: 8192 },
    { value: 16384 },
    { value: 32768 },
    { value: 65536 },
    { value: 128000 },
    { value: 1024000 }
])

// 维度建议
const suggestionDimension = shallowRef([
    { value: 256 },
    { value: 512 },
    { value: 1024 },
    { value: 1536 },
    { value: 2048 },
    { value: 3072 }
])

// 当前渠道
const currentChannels = computed<any>(() => {
    if (props.scene === 'chat') {
        return channels.value.chat_models
    } else if (props.scene === 'ranking') {
        return channels.value.ranking_models
    }
    return channels.value.vector_models
})

// 表单数据
const formData: any = reactive({
    id: '',             // 模型ID
    scene: props.scene, // 模型场景
    mark: '',           // 模型标识
    channel: '',        // 模型通道
    name: '',           // 模型名称
    logo: '',           // 模型图标
    intro: '',          // 模型描述
    config: [],         // 模型参数
    models: [],         // 模型参数
    is_disable: 0       // 是否禁用:[0=否, 1=是]
})

// 表单规则
const formRules: any = reactive({
    logo: [
        { required: true, message: '请设置模型图标', trigger: ['blur'] }
    ],
    mark: [
        { required: true, message: '请填写模型标识', trigger: 'blur' }
    ],
    channel: [
        { required: true, message: '请选择模型通道', trigger: 'blur' }
    ],
    name: [
        { required: true, message: '请填写模型名称', trigger: 'blur' }
    ],
    is_disable: [
        { required: true, message: '请选择模型状态', trigger: 'blur' }
    ]
})

/**
 * 子模型状态
 *
 * @param row
 * @author zero
 */
const handleStatus = (row: any): boolean  => {
    if (row.id && row.status === 1) {
        feedback.confirm(
            '该模型可能已经被使用，禁用后已经选择该模型的用户将无法正常使用，请谨慎操作！'
        )
        return !!row.status
    }
    return true
}

/**
 * 子模型模态
 *
 * @param row
 * @author zero
 */
const handleModal = (row: any): boolean  => {
    if (row.id && row.modal === 1) {
        return !!row.modal
    }
    return true
}

/**
 * 子模型删除
 *
 * @param index
 * @param id
 * @author zero
 */
const handleDelete = async (index: number, id: number) => {
    if (id) {
        await feedback.confirm(
            '该模型可能已经被使用，删除后已经选择该模型的用户将无法正常使用，请谨慎操作！'
        )
    }
    formData.models.splice(index, 1)
}

/**
 * 子模型创建
 *
 * @author zero
 */
const handleCreate = () => {
    if (props.scene === 'chat') {
        formData.models.push({
            model: '',
            alias: '',
            price: '',
            modal: 0,
            status: 1,
            sort: formData.models.length
        })
    } else {
        formData.models.push({
            model: '',
            alias: '',
            price: '',
            status: 1,
            sort: formData.models.length
        })
    }
}

/**
 * 提交保存
 *
 * @author zero
 */
const handleSubmit = async (): Promise<void> => {
    await formRef.value?.validate().then(async () => {
        let config: any = {}
        let params: any = Object.assign({}, formData)
        formData.config.forEach((item: any) => {
            if (item.type === 'group') {
                item.config.forEach((sub: any) => {
                    config[sub.key] = sub.default
                })
            } else {
                config[item.key] = item.default
            }
        })

        loading.value = true
        params.config = config
        if (props.type === 'edit') {
            await aiModelsApi.edit(params)
                .finally(() => {
                    setTimeout(() => {
                        loading.value = false
                    }, 600)
                })
        } else {
            delete params.id
            await aiModelsApi.add(params)
                .finally(() => {
                    setTimeout(() => {
                        loading.value = false
                    }, 600)
                })
        }

        feedback.msgSuccess('保存成功')
        setTimeout(() => {
            emits('listen', props.scene, 'lists', 0)
        }, 400)
    }).catch(() => {})
}

/**
 * 切换AI通道
 *
 * @param {string} val
 * @author zero
 */
const changeChannel = (val: string) => {
    const data = currentChannels.value[val]
    formData.config = data.configs
}

/**
 * 初始化拖拽排序
 *
 * @author zero
 */
const initSortable = () => {
    nextTick(() => {
        const el = tableRef.value?.$el.querySelector('.el-table__body tbody')
        if (!el) {
            return
        }

        Sortable.create(el, {
            animation: 150,
            handle: '.move-icon',
            onEnd: ({ newIndex, oldIndex }: any) => {
                if (newIndex === oldIndex) {
                    return
                }

                const newModels = [...formData.models]
                const currRow = newModels.splice(oldIndex, 1)[0]
                newModels.splice(newIndex, 0, currRow)

                // 强制更新数组
                formData.models = []
                nextTick(() => {
                    formData.models = newModels
                })
            }
        })
    })
}

// 监听 models 数组变化
watch(
    () => formData.models,
    () => {
        nextTick(() => {
            initSortable()
        })
    }, { deep: true }
)

onMounted(async () => {
    formData.scene = props.scene
    channels.value = await aiModelsApi.channel()
    if (props.type === 'edit') {
        const data = await aiModelsApi.detail(props.id)
        for (const key in formData) {
            if (data[key] !== null && data[key] !== undefined) {
                formData[key] = data[key]
            }
        }
    } else if (props.type === 'add') {
        handleCreate()
    }
    pageLoading.value = false
    initSortable()
})
</script>
